import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import drawing.AlgebraicLine;
import excaptions.AandBZeroException;

import regions2.BinaryRegion;
import regions2.Contour;
import regions2.RegionContourLabeling;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.Overlay;
import ij.plugin.filter.PlugInFilter;
import ij.process.ByteProcessor;
import ij.process.ImageProcessor;


public class A03_Find_Lines_In_Marker implements PlugInFilter{

	public int pixelThreshold = 25;
	public double thNewLine = 10;
	public double thOnLine = 4;
	
	public int setup(String arg, ImagePlus im) {
		return DOES_8G + DOES_RGB + NO_CHANGES;
    }
	
	
	public void run(ImageProcessor ip) {
		//Convert color into grayscale
		ByteProcessor ip2 = (ByteProcessor) ip.convertToByte(false);
		ImageProcessor ipdebug = ip.duplicate();
		
		ip2.autoThreshold();
		ip2.invert();
		(new ImagePlus("convert", ip2)).show();
		
		ipdebug = ipdebug.convertToRGB();
		
		//Create region labeler / contour tracer
		RegionContourLabeling segmenter = new RegionContourLabeling(ip2);
		
		//sort list
		List<BinaryRegion> regions = segmenter.getRegions(true);
		List<BinaryRegion> marker = new ArrayList<BinaryRegion>();
		for(int i = 0; i< regions.size(); i++) 
		{
//			IJ.log("Label: "+regions.get(i).getLabel()+" Size: " + regions.get(i).getSize());
			if(regions.get(i).getInnerContours() != null && regions.get(i).getInnerContours().size() > 0 && regions.get(i).getSize() > 3000)
			{
//				IJ.log("MarkerLabel : "+regions.get(i).getLabel());
				marker.add(regions.get(i));
			}
		}
		
		IJ.log("Anzahl der Marker: "+marker.size());
		
		//Obtain the outer contour of the largest region
		for(int i = 0; i < marker.size(); i++)
		{
			Contour oc = marker.get(i).getOuterContour();
			
			Point[] points = oc.getPointArray();
			
			try {
				ipdebug = findAndDrawConturs(ipdebug, points);
			} catch (AandBZeroException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		
		
		(new ImagePlus("Debug algebraic linein Marker", ipdebug)).show();
		
		
		
		(new ImagePlus("Find algebraic linein Marker", ip2)).show();
	}
	
	public ImageProcessor findAndDrawConturs(ImageProcessor cip, Point[] po) throws AandBZeroException
	{
		IJ.log("Alle punkte: "+po.length);
		List<AlgebraicLine> contorLines = new ArrayList<AlgebraicLine>();
		List<Point> line1 = new ArrayList<Point>();
		List<Point> line2 = new ArrayList<Point>();
		List<Point> line3 = new ArrayList<Point>();
		List<Point> line4 = new ArrayList<Point>();
		
		List<Point> tenpointsList = new ArrayList<Point>();
		for(int i = 10; i < 20; i++) {
			tenpointsList.add(po[i]);
		}
		AlgebraicLine tempContorLine = new AlgebraicLine(tenpointsList);
		
		int firstOtherPoint = -1;
		//Find first point which is not on the temp Line
		for(int i = 10; i < po.length; i++) 
		{
			//IJ.log("Distance: "+tempContorLine.distance(points[i]));
			if(Math.abs(tempContorLine.distance(po[i])) <= thOnLine)
			{
			} else if(Math.abs(tempContorLine.distance(po[i])) > thNewLine && firstOtherPoint == -1)
			{
				firstOtherPoint = i-1;
				break;
			}
		}
		IJ.log("Other point: "+po[firstOtherPoint].x + " | "+po[firstOtherPoint].y);
		
		//first line
		tenpointsList = new ArrayList<Point>();
		for(int i = firstOtherPoint; i < firstOtherPoint + 20; i++)
		{
			tenpointsList.add(po[i]);
		}
		tempContorLine = new AlgebraicLine(tenpointsList);
//		(new ImagePlus("linie der ersten 10 punkte", tempContorLine.draw(cip, Color.magenta))).show();
		int start = firstOtherPoint;
		firstOtherPoint = -1;
		for(int i = start; i < po.length; i++)
		{
			IJ.log("D: "+Math.abs(tempContorLine.distance(po[i])));
			if(Math.abs(tempContorLine.distance(po[i])) <= thOnLine)
			{
				line1.add(po[i]);
			} else if(Math.abs(tempContorLine.distance(po[i])) > thNewLine && firstOtherPoint == -1)
			{
				firstOtherPoint = i-1;
			}
		}
//		IJ.log("Line1: " + line1.size());
//		contorLines.add(new AlgebraicLine(line1.get(0), line1.get(line1.size()-1)));
		contorLines.add(new AlgebraicLine(line1));
		IJ.log("Last Point Line1 x: "+po[firstOtherPoint].x + " | "+po[firstOtherPoint].y);
		
		//secound line
		tenpointsList = new ArrayList<Point>();
//		IJ.log("Line2 start: "+firstOtherPoint);
		for(int i = firstOtherPoint; i < firstOtherPoint + 20; i++)
		{
			tenpointsList.add(po[i]);
		}
		tempContorLine = new AlgebraicLine(tenpointsList);
		start = firstOtherPoint;
		firstOtherPoint = -1;
		int lastline2 = -1;
		for(int i = start; i < po.length; i++)
		{
			if(Math.abs(tempContorLine.distance(po[i])) <= thOnLine)
			{
				line2.add(po[i]);
				lastline2 = i;
			} else if(Math.abs(tempContorLine.distance(po[i])) > thNewLine && firstOtherPoint == -1)
			{
				firstOtherPoint = i;
			}
		}
//		IJ.log("Line2: " + line2.size());
		contorLines.add(new AlgebraicLine(line2));
		IJ.log("Last Point Line2 x: "+po[firstOtherPoint].x + " | "+po[firstOtherPoint].y);
		
		//third line
		IJ.log("Linie 3 start: "+firstOtherPoint);
		IJ.log("LastLine2: "+lastline2);
		tenpointsList = new ArrayList<Point>();
		for(int i = firstOtherPoint; i < firstOtherPoint + 20; i++)
		{
			tenpointsList.add(po[i]);
		}
		tempContorLine = new AlgebraicLine(tenpointsList);
		start = firstOtherPoint;
		firstOtherPoint = -1;
		int lastLine3 = -1;
		for(int i = 0; i < po.length; i++)
		{
			if(Math.abs(tempContorLine.distance(po[i])) <= thOnLine)
			{
				line3.add(po[i]);
				lastLine3 = i;
			} else if(Math.abs(tempContorLine.distance(po[i])) > thNewLine && firstOtherPoint == -1)
			{
				firstOtherPoint = i;
			}
		}
		IJ.log("Last Point Line3 x: "+po[lastLine3].x + " | "+po[lastLine3].y);
		contorLines.add(new AlgebraicLine(line3));
		
		//forthline
		IJ.log("Linie 4 start: "+(lastLine3+1));
		IJ.log("LastLine3: "+lastLine3);
		tenpointsList = new ArrayList<Point>();
		start = firstOtherPoint-1;
		int end = firstOtherPoint+20;
		if(firstOtherPoint+1 == po.length || firstOtherPoint+20 >= po.length) 
		{
			start = 0;
			end = 20;
		}
		for(int i = start; i < end; i++)
		{
			tenpointsList.add(po[i]);
		}
		tempContorLine = new AlgebraicLine(tenpointsList);
		for(int i = 0; i < po.length; i++)
		{
			if(Math.abs(tempContorLine.distance(po[i])) <= thOnLine)
			{
				line4.add(po[i]);
			} 
		}
		IJ.log("Line4: " + line4.size());
		contorLines.add(new AlgebraicLine(line4));
		
		AlgebraicLine aLine1 = contorLines.get(0);
//		cip = aLine1.draw(cip, Color.red);
		AlgebraicLine aLine2 = contorLines.get(1);
//		cip = aLine2.draw(cip, Color.blue);
		AlgebraicLine aLine3 = contorLines.get(2);
//		cip = aLine3.draw(cip, Color.green);
		AlgebraicLine aLine4 = contorLines.get(3);
//		cip = aLine4.draw(cip, Color.yellow);
		
		List<Point> cornerPoints = new ArrayList<Point>();
		cornerPoints.add((Point) aLine1.intersect(aLine2));
		cornerPoints.add((Point) aLine2.intersect(aLine3));
		cornerPoints.add((Point) aLine3.intersect(aLine4));
		cornerPoints.add((Point) aLine4.intersect(aLine1));
		
		for(int i = 0; i < cornerPoints.size(); i++) 
		{
			if(cornerPoints.get(i) == null)
			{
				IJ.log("no intersection : " +(i+1)+(i+2));
			}
		}
		
		cip.setColor(Color.green);
		cip.drawRect(cornerPoints.get(0).x, cornerPoints.get(0).y, cornerPoints.get(2).x-cornerPoints.get(0).x, cornerPoints.get(2).y-cornerPoints.get(0).y);
//		cip.drawLine(cornerPoints.get(0).x, cornerPoints.get(0).y, cornerPoints.get(1).x, cornerPoints.get(1).y);
//		cip.drawLine(cornerPoints.get(1).x, cornerPoints.get(1).y, cornerPoints.get(2).x, cornerPoints.get(2).y);
//		cip.drawLine(cornerPoints.get(2).x, cornerPoints.get(2).y, cornerPoints.get(3).x, cornerPoints.get(3).y);
//		cip.drawLine(cornerPoints.get(3).x, cornerPoints.get(3).y, cornerPoints.get(0).x, cornerPoints.get(0).y);
		
		
		
		return cip;
	}
}
